package com.youlu.campus.service.ca.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.CaInfo;
import com.youlu.campus.entity.CaMaterialConfig;
import com.youlu.campus.entity.VO.req.CaMaterialConfigQueryVO;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.ca.CaMaterialConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CaMaterialConfigImpl implements CaMaterialConfigService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Resource(name = "masterMongoTemplate")
    private MongoTemplate masterMongoTemplate;

    @Override
    public Page<CaMaterialConfig> list(CaMaterialConfigQueryVO req) {
        log.info(":>>> 订单材质配置:{}", JSON.toJSONString(req));

        if (Objects.isNull(req)) {
            log.error(":>>> 获取订单材质配置为空");
            throw new BusinessException("订单材质配置参数错误");
        }
        if (Objects.isNull(req.getPageSize())) {
            req.setPageSize(30);
        }
        Query query = new Query();
        if (StringUtils.isNotBlank(req.getType())) {
            query.addCriteria(Criteria.where("type").is(req.getType()));
        }
        if (StringUtils.isNotBlank(req.getName())) {
            Pattern pattern = Pattern.compile("^.*" + req.getName() + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("name").regex(pattern));
        }
        if (StringUtils.isNotBlank(req.getActivityId())) {
            query.addCriteria(Criteria.where("activityId").is(req.getActivityId()));
        }
        if (StringUtils.isNotBlank(req.getActivityName())) {
            Pattern pattern = Pattern.compile("^.*" + req.getActivityName() + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("activityName").regex(pattern));
        }
        query.addCriteria(Criteria.where("deleted").ne(true));
        long count = mongoTemplate.count(query, CaMaterialConfig.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort=Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<CaMaterialConfig> infos = mongoTemplate.find(query.with(pageRequest), CaMaterialConfig.class);
        if(!CollectionUtils.isEmpty(infos)){
            infos.stream().forEach(caMaterialConfig -> {
                caMaterialConfig.setSurplusCount(caMaterialConfig.getStockCount() - caMaterialConfig.getSoldCount());
            });
        }
        return PageableExecutionUtils.getPage(infos, pageRequest, () -> count);
    }

    @Override
    public void create(CaMaterialConfig config) {
        if (Objects.isNull(config) || StringUtils.isBlank(config.getActivityId()) ||
                StringUtils.isBlank(config.getName()) || StringUtils.isBlank(config.getType()) ||
                Objects.isNull(config.getIndividuallyPacked())) {
            log.error(":>>> 创建证书材质配置参数错误");
            throw new BusinessException("创建证书材质配置参数错误");
        }
        config.setId(null);
        config.setCreatedTime(new Date());
        if (StringUtils.isNotBlank(config.getActivityId())) {
            ActivityInfo activityInfo = findActivityInfo(config.getActivityId());
            if (Objects.nonNull(activityInfo)) {
                config.setActivityName(activityInfo.getName());
            }
        }
        mongoTemplate.insert(config);
    }

    @Override
    public boolean update(CaMaterialConfig config) {
        if (Objects.isNull(config) || StringUtils.isBlank(config.getId()) || StringUtils.isBlank(config.getActivityId())) {
            log.error(":>>> 更新证书材质配置参数错误");
            throw new BusinessException("更新证书材质配置参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(config.getId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(config.getName())) {
            update.set("name", config.getName());
        }
        if (StringUtils.isNotBlank(config.getType())) {
            update.set("type", config.getType());
        }
        if (Objects.nonNull(config.getIndividuallyPacked())) {
            update.set("individuallyPacked", config.getIndividuallyPacked());
        }
        if (StringUtils.isNotBlank(config.getActivityId())) {
            update.set("activityId", config.getActivityId());
            ActivityInfo activityInfo = findActivityInfo(config.getActivityId());
            if (Objects.nonNull(activityInfo)) {
                update.set("activityName", activityInfo.getName());
            }
        }
        if (Objects.nonNull(config.getCycle())) {
            update.set("cycle", config.getCycle());
        }
        if (Objects.nonNull(config.getStockCount()) && config.getStockCount() > 0) {
            update.set("stockCount", config.getStockCount());
        }
        update.set("updatedTime", new Date());
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, CaMaterialConfig.class);
        return updateResult.getModifiedCount() > 0 ? true : false;
    }

    @Override
    public CaMaterialConfig findOne(String id) {
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        CaMaterialConfig config = mongoTemplate.findOne(query, CaMaterialConfig.class);
        return config;
    }

    @Override
    public boolean delete(String id) {
        if (!caMaterialConfigCanDelete(id)) {
            log.error(":>>> 证书材质已经生效不能删除");
            throw new BusinessException("证书材质已经生效不能删除");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("deleted", true);
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, CaMaterialConfig.class);
        return updateResult.getModifiedCount() > 0 ? true : false;
    }

    @Async
    @Override
    public void doCopyCaMaterialConfig(String copyActivityId, String activityName, String newActivityId) {
        log.info("【copy 供应链材质】开始复制供应链材质 sourceActivityId->{} | newTargetActivityId->{}", copyActivityId, newActivityId);
        Query query = new Query().addCriteria(Criteria.where("activityId").is(copyActivityId));
        List<CaMaterialConfig> materialConfigList = this.mongoTemplate.find(query, CaMaterialConfig.class);
        if (CollectionUtils.isEmpty(materialConfigList)) {
            log.error("【copy 供应链材质】结束复制供应链材质 未查询想过数据 sourceActivityId->{} | newTargetActivityId->{}", copyActivityId,
                    newActivityId);
            return;
        }
        Date now = new Date();
        List<CaMaterialConfig> targetList = materialConfigList.stream().peek(caMaterialConfig -> {
            caMaterialConfig.setId(null);
            caMaterialConfig.setActivityId(newActivityId);
            caMaterialConfig.setCreatedTime(now);
            caMaterialConfig.setUpdatedTime(now);
            caMaterialConfig.setActivityName(activityName);
        }).collect(Collectors.toList());
        this.mongoTemplate.insertAll(targetList);
        log.info("【copy 供应链材质】结束复制供应链材质 sourceActivityId->{} | newTargetActivityId->{}", copyActivityId, newActivityId);

    }

    @Override
    public void setSoldCount(String id, Integer stockNum) {
        if (StringUtils.isBlank(id) || Objects.isNull(stockNum)) {
            return;
        }
        log.info("【设置已售数量】id :{} stockNum:{}", id, stockNum);
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        update.inc("soldCount", stockNum);
        update.set("updatedTime", new Date());
        masterMongoTemplate.updateFirst(query, update, CaMaterialConfig.class);
    }

    @Override
    public Integer getSoldCount(String id) {
        if (StringUtils.isBlank(id)) {
            return 0;
        }
        CaMaterialConfig caMaterialConfig = this.masterMongoTemplate.findById(id, CaMaterialConfig.class);
        if (Objects.isNull(caMaterialConfig)) {
            return 0;
        }
        return caMaterialConfig.getSoldCount();
    }

    @Override
    public Boolean overbought(String id) {
        if (StringUtils.isBlank(id)) {
            return Boolean.FALSE;
        }
        log.info("库存是否超卖:{}",id);
        CaMaterialConfig caMaterialConfig = this.masterMongoTemplate.findById(id, CaMaterialConfig.class);
        if (Objects.isNull(caMaterialConfig)) {
            return Boolean.FALSE;
        }
        if (caMaterialConfig.getSoldCount() > caMaterialConfig.getStockCount()) {
            log.info("商品:{}库存:{} 已超卖:{}",id,caMaterialConfig.getStockCount(),caMaterialConfig.getSoldCount());
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Integer getBatchSoldCount(List<String> caMaterialIdList) {
        if(CollectionUtils.isEmpty(caMaterialIdList)){
            return 0;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("id").in(caMaterialIdList));
        List<CaMaterialConfig> caMaterialConfigList = this.mongoTemplate.find(query, CaMaterialConfig.class);
        if(CollectionUtils.isEmpty(caMaterialConfigList)){
            return 0;
        }
        return caMaterialConfigList.stream().mapToInt(CaMaterialConfig::getSoldCount).sum();
    }

    @Override
    public List<CaMaterialConfig> findByCaMaterialIdList(List<String> caMaterialIdList) {
        if(CollectionUtils.isEmpty(caMaterialIdList)){
            return new ArrayList<>();
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("id").in(caMaterialIdList));
       return this.mongoTemplate.find(query, CaMaterialConfig.class);
    }

    @Override
    public Boolean overboughtByIdAndNum(String id, Integer num) {
        if (StringUtils.isBlank(id)) {
            return Boolean.FALSE;
        }
        log.info("库存是否超卖:{},num:{}",id,num);
        CaMaterialConfig caMaterialConfig = this.masterMongoTemplate.findById(id, CaMaterialConfig.class);
        if (Objects.isNull(caMaterialConfig)) {
            return Boolean.FALSE;
        }
        int soldCount = Math.addExact(caMaterialConfig.getSoldCount(), num);
        log.info("已售:{}库存是否超卖:{},num:{}",id,soldCount);
        if (soldCount > caMaterialConfig.getStockCount()) {
            log.info("商品:{}库存:{} 已超卖:{}",id,caMaterialConfig.getStockCount(),soldCount);
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Integer getStockById(String id) {
        CaMaterialConfig caMaterialConfig = this.mongoTemplate.findById(id, CaMaterialConfig.class);
        if(Objects.nonNull(caMaterialConfig)){
            int stockNum = Math.subtractExact(caMaterialConfig.getStockCount(),caMaterialConfig.getSoldCount());
            return stockNum;
        }
        return 0;
    }

    private boolean caMaterialConfigCanDelete(String id) {
        Query query = new Query().addCriteria(Criteria.where("materialConfigId").is(id));
        boolean exist = mongoTemplate.exists(query, CaInfo.class);
        return !exist;

    }

    private ActivityInfo findActivityInfo(String id) {
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        ActivityInfo activityInfo = mongoTemplate.findOne(query, ActivityInfo.class);
        return activityInfo;
    }
}
